﻿// (c) Copyright Fernando Cerqueira.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;
using Microsoft.SmartDevice.Connectivity;
using AppRes = WindowsPhoneCommands.Resources;

// ReSharper disable CheckNamespace
namespace WindowsPhoneCommands
// ReSharper restore CheckNamespace
{
    public static class WPhoneDevice
    {
        public static Guid GuidApp(CoreNameSettings name)
        {
            switch (name)
            {
                //case CoreNameSettings.BasicSettings:
                //     return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5601");
                case CoreNameSettings.DateAndTime:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5606");
                case CoreNameSettings.LockWallpaper:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5607");
                case CoreNameSettings.Keyboard:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5608");
                case CoreNameSettings.Brightness:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA560B");
                case CoreNameSettings.RegionLanguage:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA560C");
                case CoreNameSettings.RingtoneSounds:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA560D");
                case CoreNameSettings.Theme:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA560E");
                case CoreNameSettings.EmailAccounts:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5616");
                case CoreNameSettings.PhoneCall:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA561C");
                case CoreNameSettings.CellularNetwork:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA561F");
                case CoreNameSettings.Bluetooth:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5620");
                case CoreNameSettings.AirplaneMode:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5621");
                case CoreNameSettings.Office:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5622");
                case CoreNameSettings.Wifi:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5623");
                case CoreNameSettings.Speech:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5624");
                case CoreNameSettings.InternetSharing:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5629");
                case CoreNameSettings.PhoneUpdate:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5640");
                case CoreNameSettings.Location:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5642");
                case CoreNameSettings.InternetExplorer:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5663");
                case CoreNameSettings.Search:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5664");
                case CoreNameSettings.Feedback:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5670");
                case CoreNameSettings.BatterySaver:
                    return new Guid("AFE91DD5-26FB-4ba6-A5A4-4BCEDE8FB3E6");
                case CoreNameSettings.About:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5605");
                default:
                    throw new ArgumentOutOfRangeException("name");
            }
        }

        public static Guid GuidApp(CoreNameAplications name)
        {
            switch (name)
            {
                case CoreNameAplications.Alarms:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA560A");
                case CoreNameAplications.Calendar:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5612");
                case CoreNameAplications.CallHistory:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5611");
                case CoreNameAplications.Calculator:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5603");
                case CoreNameAplications.Messaging:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5610");
                case CoreNameAplications.Zune:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5630");
                case CoreNameAplications.People:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5615");
                case CoreNameAplications.Pictures:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5632");
                case CoreNameAplications.Camera:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5631");
                case CoreNameAplications.Marketplace:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5633");
                case CoreNameAplications.Games:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5634");
                case CoreNameAplications.Office:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA561E");
                case CoreNameAplications.Maps:
                    return new Guid("5B04B775-356B-4AA0-AAF8-6491FFEA5661");
                default:
                    throw new ArgumentOutOfRangeException("name");
            }
        }

        private static Collection<Device> ListDevices()
        {
            var pla = new DatastoreManager(CultureInfo.CurrentCulture.LCID)
                .GetPlatforms()
                .First(p => p.Name == Constants.WPlataform7);
            var result = pla.GetDevices(); //.Where(d => d.Id != def.Id);
            return result;
        }

        private static Collection<Device> _avaliabledevices;

        public static Collection<Device> AvaliableDevices
        {
            get { return _avaliabledevices ?? (_avaliabledevices = ListDevices()); }
        }

        public static Collection<AppPhoneRemoteApplication> ListApplicationsCore()
        {
            var appcore = new Collection<AppPhoneRemoteApplication>();
            foreach (var app in Enum.GetNames(typeof(CoreNameAplications)))
            {
                appcore.Add(new AppPhoneRemoteApplication
                {
                    ProductId = GuidApp((CoreNameAplications)Enum.Parse(typeof(CoreNameAplications), app)).ToString(),
                    ProductName = app,
                    AliasName = app,
                    IsCoreApp = true
                });
            }
            return appcore;
        }

        public static Collection<AppPhoneRemoteApplication> ListSettingsCore()
        {
            var appcore = new Collection<AppPhoneRemoteApplication>();
            foreach (var app in Enum.GetNames(typeof(CoreNameSettings)))
            {
                appcore.Add(new AppPhoneRemoteApplication
                {
                    ProductId = GuidApp((CoreNameSettings)Enum.Parse(typeof(CoreNameSettings), app)).ToString(),
                    ProductName = app,
                    AliasName = app,
                    IsCoreApp = true
                });
            }
            return appcore;
        }

        public static Collection<AppPhoneRemoteApplication> ListApplicationsInstalled()
        {
            var appinst = new Collection<AppPhoneRemoteApplication>();
            foreach (var app in CurrentDevice.GetInstalledApplications())
            {
                var tit = app.ProductID.ToString();
                var alias = string.Empty;
                try
                {
                    if (!string.IsNullOrEmpty(app.Title))
                    {
                        tit = app.Title;
                    }
                }
                catch
                {
                    var item = WpIsolateSaveData.Current.WpApplication.FirstOrDefault(a => a.Guid == app.ProductID.ToString());
                    if (item != null)
                    {
                        tit = item.Title;
                        alias = item.RenameTitle;
                    }
                }
                if (tit == app.ProductID.ToString())
                {
                    if (!string.IsNullOrEmpty(alias))
                    {
                        tit = alias;
                    }
                }

                appinst.Add(new AppPhoneRemoteApplication{ProductId =  app.ProductID.ToString(),ProductName = tit,AliasName  = alias,  IsCoreApp = false});
            }
            return appinst;
        }

        public static Device CurrentDevice { get; private set; }

        public static SystemInfo SystemInfo { get; private set; }

        public static bool IsConnected { get; private set; }

        public static string Error { get; private set; }

        public static bool ValidateConnected()
        {
            IsConnected = CurrentDevice != null && CurrentDevice.IsConnected();
            return IsConnected;
        }

        public static void  Disconnect()
        {
            if (CurrentDevice.IsConnected())
            {
                CurrentDevice.Disconnect();
            }
            Error = string.Empty;
            IsConnected = false;
        }

        public static bool Connect(Device device)
        {
            CurrentDevice = device;
            if (CurrentDevice != null)
            {
                if (CurrentDevice.IsConnected())
                {
                    SystemInfo = CurrentDevice.GetSystemInfo();
                    IsConnected = true;
                    Error = string.Empty;
                    return true;
                }
                try
                {
                    CurrentDevice.Connect();
                    SystemInfo = CurrentDevice.GetSystemInfo();
                    IsConnected = true;
                    Error = string.Empty;
                }
                catch (Exception ex)
                {
                    Error = AppRes.CnnErr + ErroCodeDevice(ex.Message);
                    IsConnected = false;
                    CurrentDevice = null;
                    SystemInfo = null;
                }
            }

            return IsConnected;
        }

        public static IsoFilesView GetIsoFiles(string guidapp)
        {
            var remapp = CurrentDevice.GetApplication(new Guid(guidapp));
            var iso = remapp.GetIsolatedStore();
            var tit = remapp.ProductID.ToString();
            try
            {
                if (!string.IsNullOrEmpty(remapp.Title))
                {
                    tit = remapp.Title;
                }
            }
            catch
            {
                var item = WpIsolateSaveData.Current.WpApplication.FirstOrDefault(a => a.Guid == remapp.ProductID.ToString());
                if (item != null)
                {
                    tit = item.Title;
                }
            }

            var root = new IsoFilesView(remapp.ProductID.ToString()) { IsRoot = true, Files = GetIsoDir(guidapp, iso, "\\"), Name = tit };
            return root;
        }

        public static string GetIsolatedStoreRootPath(string guidapp)
        {
            return string.Format(Constants.RootIsoTemplate, guidapp);
        }

        private static IsoFilesView[] GetIsoDir(string guidapp, RemoteIsolatedStorageFile isofile, string path)
        {
            var template = GetIsolatedStoreRootPath(guidapp);
            var result = new List<IsoFilesView>();
            try
            {
                var files = isofile.GetDirectoryListing(path);
                foreach (var remoteFileInfo in files)
                {
                    if (remoteFileInfo.IsDirectory())
                    {
                        var dirName = remoteFileInfo.Name.Replace(template, "").Replace(path, "").Replace("\\","");
                        var system = false;
                        var folder = remoteFileInfo.Name.Replace(template, "");
                        switch (folder)
                        {
                            case "\\\\Shared":
                                system = true;
                                break;
                            case "\\\\Shared\\Transfers":
                                system = true;
                                break;
                            case "\\\\Shared\\ShellContent":
                                system = true;
                                break;
                            case "\\\\Shared\\Media":
                                system = true;
                                break;
                        }
                        var item = new IsoFilesView(guidapp)
                                       {
                                Files = null, 
                                Length = remoteFileInfo.Length, 
                                DateAccess =  remoteFileInfo.LastAccessTime,
                                DateCreated = remoteFileInfo.CreationTime,
                                DateWrite = remoteFileInfo.LastWriteTime,
                                IsDiretory = true, 
                                IsSystem = system,
                                FullName = remoteFileInfo.Name,
                                Icon = string.Empty,
                                Name = dirName
                            };
                        item.Files = GetIsoDir(guidapp, isofile, remoteFileInfo.Name.Replace(template, ""));
                        result.Add(item);
                    }
                    else
                    {
                        var fileName = remoteFileInfo.Name.Replace(template, "").Replace(path, "").Replace("\\", "");
                        result.Add(new IsoFilesView(guidapp)
                        {
                            Files = null, 
                            Length = remoteFileInfo.Length,
                            DateAccess = remoteFileInfo.LastAccessTime,
                            DateCreated = remoteFileInfo.CreationTime,
                            DateWrite = remoteFileInfo.LastWriteTime,
                            IsDiretory = false,
                            FullName = remoteFileInfo.Name,
                            Icon = string.Empty,
                            Name = fileName
                        });
                    }
                }
            }
            // ReSharper disable EmptyGeneralCatchClause
            catch (Exception)
            // ReSharper restore EmptyGeneralCatchClause
            {
                //no files
            }
            return result.Count != 0 ? result.ToArray() : null;
        }

        public static string CopySendFile(string guidapp, IsoFilesView isofileinfo, string newfile, bool overwrite)
        {
            var template = GetIsolatedStoreRootPath(guidapp);
            var remapp = CurrentDevice.GetApplication(new Guid(guidapp));
            var iso = remapp.GetIsolatedStore();
            var pathfolder = string.Empty;
            if (!isofileinfo.IsRoot)
            {
                pathfolder = isofileinfo.FullName.Replace(template, "");
            }
            var fi = new FileInfo(newfile);
            pathfolder += "\\" + fi.Name;
            if (iso.FileExists(pathfolder) && !overwrite)
            {
                return AppRes.FileExist;
            }
            var filereadonly = fi.IsReadOnly;
            //change attribute (prevent error when delete)
            fi.IsReadOnly = false;
            iso.SendFile(newfile, pathfolder, overwrite);
            //change attribute (restore original attribute)
            fi.IsReadOnly = filereadonly;
            return string.Empty;
        }

        public static string CopyReceiveFile(string guidapp, IsoFilesView isofileinfo, string desktopTarget)
        {
            var template = GetIsolatedStoreRootPath(guidapp);
            var remapp = CurrentDevice.GetApplication(new Guid(guidapp));
            var iso = remapp.GetIsolatedStore();
            var filepath = isofileinfo.FullName.Replace(template, "");
            var deskDirinfo = new DirectoryInfo(desktopTarget);
            if (!isofileinfo.IsRoot)
            {
                deskDirinfo = CreateDesktopSubdirectory(guidapp, desktopTarget, isofileinfo, isofileinfo.Name);
            }

            var targetfile = Path.Combine(deskDirinfo.FullName, isofileinfo.Name);
            iso.ReceiveFile(filepath, targetfile, true);
            return deskDirinfo.FullName;
        }

        public static void RenameFile(string guidapp, IsoFilesView isofileinfo, string newfile)
        {
            var template = GetIsolatedStoreRootPath(guidapp);
            var remapp = CurrentDevice.GetApplication(new Guid(guidapp));
            var iso = remapp.GetIsolatedStore();
            var pathfolder = string.Empty;
            if (!isofileinfo.IsRoot)
            {
                pathfolder = isofileinfo.FullName.Replace(template, "");
            }
            var filetemp = Path.GetTempPath() + "\\" + newfile;
            var newpathfile = pathfolder.Replace(isofileinfo.Name,newfile);
            iso.ReceiveFile(pathfolder, filetemp, true);
            iso.SendFile(filetemp, newpathfile, true);
            iso.DeleteFile(pathfolder);
            if (File.Exists(filetemp))
            {
                File.Delete(filetemp);
            }
        }

        public static string DeleteFile(string guidapp, IsoFilesView isofileinfo, string file)
        {
            var template = GetIsolatedStoreRootPath(guidapp);
            var remapp = CurrentDevice.GetApplication(new Guid(guidapp));
            var iso = remapp.GetIsolatedStore();
            var pathfolder = string.Empty;
            if (isofileinfo.IsDiretory || isofileinfo.IsRoot)
            {
                //folder info
                if (!isofileinfo.IsRoot)
                {
                    pathfolder = isofileinfo.FullName.Replace(template, "");
                }
                pathfolder += "\\" + file;
            }
            else
            {
                //file info
                pathfolder = isofileinfo.FullName.Replace(template, "");
            }
            if (!iso.FileExists(pathfolder))
            {
                return AppRes.FileNotExist;
            }
            iso.DeleteFile(pathfolder);
            return string.Empty;

        }

        public static void DeleteIsoDir(string guidapp, IsoFilesView isofileinfo)
        {
            var remapp = CurrentDevice.GetApplication(new Guid(guidapp));
            var iso = remapp.GetIsolatedStore();
            var template = GetIsolatedStoreRootPath(guidapp);
            var pathfolder = string.Empty;
            if (isofileinfo != null)
            {
                pathfolder = isofileinfo.FullName.Replace(template, "");
            }
            iso.DeleteDirectory(pathfolder);
        }

        public static void CreateIsoDir(string guidapp, IsoFilesView isofileinfo, string newfolder)
        {
            var template = GetIsolatedStoreRootPath(guidapp);
            var remapp = CurrentDevice.GetApplication(new Guid(guidapp));
            var iso = remapp.GetIsolatedStore();
            var pathfolder = string.Empty;
            if (!isofileinfo.IsRoot)
            {
                pathfolder = isofileinfo.FullName.Replace(template + "\\", "");
            }
            pathfolder += "\\" + newfolder;
            if (iso.DirectoryExists(pathfolder))
            {
                throw new IOException(AppRes.FolderExist);
            }
            iso.CreateDirectory(pathfolder);
        }

        private static DirectoryInfo CreateDesktopSubdirectory(string guidapp,string rootTarget, IsoFilesView isofileinfo,string filename)
        {
            var template = GetIsolatedStoreRootPath(guidapp);
            var folderpath = isofileinfo.FullName.Replace(template, "");
            if (!string.IsNullOrEmpty(filename))
            {
                folderpath = folderpath.Replace(filename, "");
            }

            var folders = folderpath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);

            var destotoptarget = new DirectoryInfo(rootTarget);
            foreach (var item in folders)
            {
                if (!Directory.Exists(Path.Combine(destotoptarget.FullName, item)))
                {
                    destotoptarget = destotoptarget.CreateSubdirectory(item);
                }
            }

            return destotoptarget;
        }

        public static string[] CopyIsoDir(string guidapp, IsoFilesView isofileinfo, string desktopTarget,bool onlySelected,  ref int qtddir, ref int qtdfiles)
        {
            var deskDirinfo = new DirectoryInfo(desktopTarget);
            if (!isofileinfo.IsRoot)
            {
                deskDirinfo = CreateDesktopSubdirectory(guidapp,desktopTarget,isofileinfo,"");
            }
            return ExecuteCopyIsoDir(guidapp, isofileinfo.Files, deskDirinfo,onlySelected, ref qtddir, ref qtdfiles);
        }

        private static string[] ExecuteCopyIsoDir(string guidapp, IEnumerable<IsoFilesView> files, DirectoryInfo destotoptarget, bool onlySelected, ref int qtddir, ref int qtdfiles)
        {
            if (files == null) return new string[]{};
            
            var remapp = CurrentDevice.GetApplication(new Guid(guidapp));
            var iso = remapp.GetIsolatedStore();
            var template = GetIsolatedStoreRootPath(guidapp);
            var result = new List<string>();
            foreach (var item in files)
            {
                if (item.IsDiretory)
                {
                    if (onlySelected)
                    {
                        if (item.Seleted)
                        {
                            var subdirectory = destotoptarget.CreateSubdirectory(item.Name);
                            qtddir++;
                            result.AddRange(ExecuteCopyIsoDir(guidapp, item.Files, subdirectory, true, ref qtddir, ref qtdfiles));
                        }
                    }
                    else
                    {
                        var subdirectory = destotoptarget.CreateSubdirectory(item.Name);
                        qtddir++;
                        result.AddRange(ExecuteCopyIsoDir(guidapp, item.Files, subdirectory, false, ref qtddir, ref qtdfiles));
                    }
                }
                else
                {
                    try
                    {
                        var filepath = item.FullName.Replace(template, "");
                        var targetfile = Path.Combine(destotoptarget.FullName, item.Name);
                        if (onlySelected)
                        {
                            if (item.Seleted)
                            {
                                iso.ReceiveFile(filepath, targetfile, true);
                                qtdfiles++;
                            }
                        }
                        else
                        {
                            iso.ReceiveFile(filepath, targetfile, true);
                            qtdfiles++;
                        }
                    }
                    catch (Exception ex)
                    {
                        result.Add(string.Format(AppRes.MsgErroFile,item.Name,ex.Message));
                    }
                }
            }
            return result.ToArray();
        }

        public static string[] DeleteSelectedIsoDir(string guidapp, IEnumerable<IsoFilesView> files, ref int qtdfiles)
        {
            if (files == null) return new string[] { };

            var remapp = CurrentDevice.GetApplication(new Guid(guidapp));
            var iso = remapp.GetIsolatedStore();
            var template = GetIsolatedStoreRootPath(guidapp);
            var result = new List<string>();
            foreach (var item in files)
            {
                if (item.IsDiretory || item.IsRoot)
                {
                    if (item.Seleted)
                    {
                        result.AddRange(DeleteSelectedIsoDir(guidapp, item.Files, ref qtdfiles));
                    }
                }
                else
                {
                    try
                    {
                        if (item.Seleted)
                        {
                            var pathfolder = item.FullName.Replace(template, "");
                            iso.DeleteFile(pathfolder);
                            qtdfiles++;
                        }
                    }
                    catch (Exception ex)
                    {
                        result.Add(string.Format(AppRes.MsgErroFile, item.Name, ex.Message));
                    }
                }
            }
            return result.ToArray();
        }

        public static string ErroCodeDevice(string errocode)
        { 
            switch (errocode.ToUpper())
            {
                case "0X8973180E":
                    return AppRes.Err0X8973180E;
                case "0X8973180F":
                    return AppRes.Err0X8973180F;
                case "0X89731811":
                    return AppRes.Err0X89731811;
                case "0X89740006":
                    return AppRes.Err0X89740006;
                case "0X89731812":
                    return AppRes.Err0X89731812;
                case "0X89731813":
                    return AppRes.Err0X89731813;
                case "0X81030110":
                    return AppRes.Err0X81030110;
                case "0X81030118":
                    return AppRes.Err0X81030118;
                case "0X81030119":
                    return AppRes.Err0X81030119;
            }
            return errocode;
        }

    }
}
